package edu.faytechcc.csc251.elementalTD;

import java.awt.*;
import java.awt.image.*;
import java.util.ArrayList;
import javax.swing.*;

/**
 * Gathers all images, creates thread, spawns mobs, draws objects to panel
 * 10/10/2013 CIS 251
 *
 * @author William Robles
 */
public class GameDisplay extends JPanel implements Runnable
{

    public Thread thread = new Thread(this);
    public static int myWidth, myHeight;
    
    private static boolean isFirst = true;
    public static boolean isDebug = false;
    
    private static JTextArea battleLog;
    private static JScrollPane battlePane;
    private static String newLine = "\n";
    
    private static Rectangle startButton,quitButton;
    private static boolean startGame = false;
    private static boolean quitGame = false;
    private final int startButSize = 50;
    private Image startButtonGfx;
    
    public static boolean mouseDown;
    
    public static Point mse = new Point(0, 0);
    
    public static Image[] tile_groundTex = new Image[10];
    public static Image[] upperLevel = new Image[100];
    public static Image[] tile_shopButton = new Image[20];
    public static Image[] tile_statusIcons = new Image[10];
    public static Image[] tile_mobs = new Image[50];
    
    public static int groundGrass = 0;   
    public static int groundDirt = 1;
    public static int groundGrassDirt = 2;
    public static int exitDirt = 3;
    
    private static int[][] mobInfo = new int[50][10];
    private static int level;
    private static final int HEALTH = 1, GOLD = 2, QTY = 3, ICON = 4, SPEED = 5;
    public static int playerHealth = 20, playerTree, playerScore, playerCash = 40;
    
    public static Map map;
    private static LoadFile load;
    public static GameComponents gameComps;
    
    private static ArrayList<Mob> mobsNotInGame = new ArrayList<>();
    private static ArrayList<Mob> mobsInGame = new ArrayList<>();
    private static ArrayList<Mob> deadMobs = new ArrayList<>();

    public GameDisplay(Frame frame)
    {
        frame.addMouseListener(new ActionHandle());
        frame.addMouseMotionListener(new ActionHandle());
        frame.addKeyListener(new ActionHandle());
        
        this.setLayout(null);
        
        battleLog = new JTextArea(6, 1);
        battleLog.setEditable(false);
        battleLog.setFocusable(false);
        battleLog.setFont(new Font("Times New Roman", Font.BOLD, 12));
        battlePane = new JScrollPane(battleLog);
        this.add(battlePane);
        

        thread.start();
    }

    /**
     * define method creates Map, LoadMap, Store objects and loads up arrays
     * with images
     *
     * gets images from "res" folder and crops them
     */
    public void define()
    {
        map = new Map();
        load = new LoadFile();
        gameComps = new GameComponents();      
         battlePane.setBounds(map.block[0][0].x, map.block[map.worldWidth][0].y +
                                                    map.blockSize + 2,
                                                    map.worldWidth * map.blockSize - (map.blockSize*2) - 4 , 80);
        battleLog.setText(newLine + "    Welcome to SwitchmoD's Java Tower Defense");
        battleLog.append(newLine + newLine + "**TIP*Press space bar to show/hide mob HP*TIP**");

        level = 0;
        playerCash = 40;
        playerHealth = 20;
        playerTree = 0;
        playerScore = 0;
        
        this.setBorder(BorderFactory.createEtchedBorder(Color.BLACK,Color.DARK_GRAY));

        // loads array for ground textures and crops to fit 12x12
        for (int i = 0; i < tile_groundTex.length; i++)
        {
            tile_groundTex[i] = new ImageIcon("res/tile_groundTex.png").getImage();
            tile_groundTex[i] = createImage(new FilteredImageSource(tile_groundTex[i].getSource(),
                    new CropImageFilter(0, 12 * i, 12, 12)));
            // loads array for mob textures and crops to fit 12x12
            tile_mobs[i] = new ImageIcon("res/tile_mobs.png").getImage();
            tile_mobs[i] = createImage(new FilteredImageSource(tile_mobs[i].getSource(),
                    new CropImageFilter(0, 12 * i, 12, 12)));
        }

        // loads array for air textures and crops to fit 12x12
        // air textures are placed on top of grass areas
        for (int i = 0; i < upperLevel.length; i++)
        {
            upperLevel[i] = new ImageIcon("res/tile_upperLevel.png").getImage();
            upperLevel[i] = createImage(new FilteredImageSource(upperLevel[i].getSource(),
                    new CropImageFilter(0, 12 * i, 12, 12)));
        }

        // loads array for shop textures and crops to fit 12x12
        tile_shopButton[0] = new ImageIcon("res/tile_shopButton.png").getImage();

        // loads array for status icons
        tile_statusIcons[0] = new ImageIcon("res/iconCoin.png").getImage();
        tile_statusIcons[1] = new ImageIcon("res/iconHeart.png").getImage();
        tile_statusIcons[2] = new ImageIcon("res/iconTree.png").getImage();


        load.loadMap();

        mobInfo = load.loadMobStat().clone();

        unSpawnedMobs();
    }

    /**
     * defines the paintComponent method to paint everything on the JPanel
     *
     * also draws border around map
     *
     * @param g
     */
    @Override
    public synchronized void paintComponent(Graphics g)
    {
        if (isFirst)
        {
            myWidth = this.getWidth();
            myHeight = this.getHeight();
            define();

            isFirst = false;
        }

        g.setColor(new Color(30, 30, 30));
        g.fillRect(0, 0, getWidth(), getHeight());
        g.setColor(Color.black);

        // Creates border around map
        g.drawLine(map.block[0][0].x - 1, map.block[0][0].y, map.block[0][0].x - 1, map.block[map.worldHeight - 1][0].y + map.blockSize);
        g.drawLine(map.block[0][map.worldWidth - 1].x + map.blockSize, map.block[0][0].y, map.block[0][map.worldWidth - 1].x + map.blockSize,
                map.block[map.worldHeight - 1][0].y + map.blockSize);
        g.drawLine(map.block[0][0].x, map.block[map.worldHeight - 1][0].y + map.blockSize, map.block[0][map.worldWidth - 1].x + map.blockSize,
                map.block[map.worldHeight - 1][0].y + map.blockSize);
        g.drawLine(map.block[0][0].x - 1, map.block[0][0].y - 1, map.block[0][map.worldWidth - 1].x + map.blockSize,
                map.block[0][0].y - 1);

        map.draw(g);
        

        for (Mob mob : mobsInGame)
        {
            mob.draw(g);
        }

        gameComps.draw(g);
        gameStatusButtons(g);
        
        if (playerHealth < 1)
        {
            g.setColor(new Color(0, 0, 0, 150));
            g.fillRect(0, 0, myWidth, myHeight);
        }
    }
    
    /**
     * deadMob method checks if mob is dead and if it isnt 
     * removes the mob.
     */
    public void deadMob()
    {
        ArrayList<Mob> removeMe = new ArrayList<>();
        for (Mob mob : mobsInGame)
        {

            if (mob.isDead())
            {
                deadMobs.add(mob);
                playerScore += mobInfo[level][GOLD];
                playerCash += mobInfo[level][GOLD];
            } else if (!mob.isInGame())
            {
                removeMe.add(mob);
            } else
            {
                mob.movement();
            }
        }


        mobsInGame.removeAll(deadMobs);
        mobsInGame.removeAll(removeMe);
        mobsNotInGame.addAll(removeMe);
        removeMe.clear();
    }
    /**
     * mobSpawner method spawns a mob using spawnTime and spawnClock
     *
     * also type of mob is based on Value class
     */
    public int spawnTime = 400, spawnClock = 0;

    public synchronized void mobSpawner()
    {

        if (spawnClock >= spawnTime)
        {
            if (!mobsNotInGame.isEmpty())
            {
                Mob releaseMe = mobsNotInGame.remove(0);
                releaseMe.spawnMob(mobInfo[level][ICON]);
                mobsInGame.add(releaseMe);
            }

            spawnClock = 0;
        } else
        {
            spawnClock++;
        }
    }

    /**
     * gameOver method pops up a window to restart or quit
     */
    public void gameOver()
    {
        Object[] options =
        {
            "Restart",
            "Quit"
        };

        if (playerHealth <= 0)
        {
            int reply = JOptionPane.showOptionDialog(null, "You LOSE!!!", "Retry or Quit",
                    JOptionPane.YES_NO_OPTION,
                    JOptionPane.WARNING_MESSAGE, null,
                    options, options[1]);

            if (reply == JOptionPane.NO_OPTION)
            {
                System.exit(0);
            } else
            {
                restartGame();

            }
        }
    }

    /**
     * restartGame method sets default values and calls the define method
     */
    private void restartGame()
    {
        startGame = false;
        mobsNotInGame.clear();
        mobsInGame.clear();
        deadMobs.clear();
        battleLog.setText(null);
        define();
    }

    /**
     * loadNextLvl method resets mob containers and increments levels
     */
    private void loadNextLvl()
    {
        level++;
        mobsNotInGame.clear();
        deadMobs.clear();
        unSpawnedMobs();

    }

    /**
     * run method is defined to create a thread so that the mobs are spawn and
     * move around and linked to physics in map
     *
     * also runs gameOver depending on life and if the paintComponet is defined
     */
    @Override
    public void run()
    {
        while (true)
        {
            if(quitGame)
            {
                System.exit(0);
            }
            
            if (!isFirst && playerHealth > 0)
            {
                                
                if (startGame == true)
                {
                    mobSpawner();
                }

                deadMob();

                if (deadMobs.size() == mobInfo[level][QTY])
                {
                    loadNextLvl();
                }
            } else
            {
                gameOver();
            }

            repaint();

            try
            {
                Thread.sleep(1);
            } catch (Exception e)
            {
            }
        }
        
    }

    /**
     * unSpawnedMobs method adds mobs into arraylist based on data from array
     * file
     */
    private void unSpawnedMobs()
    {
        for (int i = 0; i < mobInfo[level][QTY]; i++)
        {
            mobsNotInGame.add(new Mob(mobInfo[level][HEALTH]));
        }
        startGame = false;
    }
    
    
    /**
     * gameStatusButtons creates the reset, start & quit buttons
     * @param g 
     */
    private void gameStatusButtons(Graphics g)
    {
         startButtonGfx = new ImageIcon("res/startButton.png").getImage();
        // Create start button
        startButton = new Rectangle(GameDisplay.map.worldWidth * GameDisplay.map.blockSize - 42,
                GameDisplay.map.worldHeight * GameDisplay.map.blockSize + 32, startButSize, startButSize);
        quitButton = new Rectangle(GameDisplay.map.worldWidth * GameDisplay.map.blockSize - 42,
                GameDisplay.map.worldHeight * GameDisplay.map.blockSize + 82, startButSize, startButSize -20);
        
        // Draw start button
        g.setColor(Color.RED);
        g.fillRect(startButton.x, startButton.y, startButton.width, startButton.height);
        // Draw quit button
        g.setColor(Color.YELLOW);
        g.fillRect(quitButton.x, quitButton.y, quitButton.width, quitButton.height);
        // Highlights button when hover overed
        if (startButton.contains(mse))
        {
            g.setColor(new Color(0, 0, 0, 100));
            g.fillRect(startButton.x, startButton.y, startButton.width, startButton.height);
        }
        else if (quitButton.contains(mse))
        {
            g.setColor(new Color(0, 0, 0, 100));
            g.fillRect(quitButton.x, quitButton.y, quitButton.width, quitButton.height);
        }
        g.drawImage(startButtonGfx, startButton.x, startButton.y, startButton.width, startButton.height, null);
        g.drawImage(startButtonGfx, quitButton.x, quitButton.y, quitButton.width, quitButton.height, null);
        g.setColor(Color.BLACK);
        g.setFont(new Font("Courier New", Font.BOLD, 12));
        g.drawString("Start", startButton.x + 8, startButton.y + 28);
        g.drawString("Quit", startButton.x + 12, startButton.y + 70);
    }
    
    /**
     * The click method allows action events for mouse
     * @param click 
     */
    public static void click(int click)
    {
        if (startButton.contains(mse) && click >= 500)
        {
            
            addBattleLog(newLine + "Level: " + mobInfo[level][0] +
                    " Mob Life: " + mobInfo[level][HEALTH] + 
                    " Gold Value: " + mobInfo[level][GOLD]);
            startGame = true;
        }
        else if (quitButton.contains(mse) && click >= 500)
        {
            quitGame = true;
        }
    }
    
    private static void addBattleLog(String str)
    {
        if(level == 0)
        {
            battleLog.setText(null);
        }
        battleLog.append(str);
    }
    
    public static int getMobGold()
    {
        return mobInfo[level][GOLD];
    }
    
    public static ArrayList getMobsInGame()
    {     
            return mobsInGame;       
    }
}
